#include "i2c.h"

#ifdef __cplusplus
 extern "C" {
#endif

/******************************************************************************/
Status_I2C InitLowLevel_I2C(I2C_TypeDef* I2Cx)
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  I2C_InitTypeDef  I2C_InitStructure;
  
  I2C_DeInit(I2Cx);
  
  /* GPIO */
  /* I2C Periph clock enable */
  RCC_APB1PeriphClockCmd(I2C_CLK, ENABLE);
  
  /* I2C_SCL_GPIO_CLK and I2C_SDA_GPIO_CLK Periph clock enable */
  RCC_AHB1PeriphClockCmd(I2C_SCL_GPIO_CLK | I2C_SDA_GPIO_CLK, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
  
  /* Reset I2C IP */
  RCC_APB1PeriphResetCmd(I2C_CLK, ENABLE);
  
  /* Release reset signal of I2C IP */
  RCC_APB1PeriphResetCmd(I2C_CLK, DISABLE);
 
  /* GPIO configuration */
  /* Connect PXx to I2C_SCL*/
  GPIO_PinAFConfig(I2C_SCL_GPIO_PORT, I2C_SCL_SOURCE, I2C_SCL_AF);
  /* Connect PXx to I2C_SDA*/
  GPIO_PinAFConfig(I2C_SDA_GPIO_PORT, I2C_SDA_SOURCE, I2C_SDA_AF);  
  
  /* Configure I2C pins: SCL */   
  GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
  GPIO_Init(I2C_SCL_GPIO_PORT, &GPIO_InitStructure);

  /* Configure I2C pins: SDA */
  GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN;
  GPIO_Init(I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
  
  /* I2C */
  /* I2C configuration */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;  
  
  /* I2C Peripheral Enable */
  I2C_Cmd(I2Cx, ENABLE);
  /* Apply I2C configuration after enabling it */
  I2C_Init(I2Cx, &I2C_InitStructure); 
  
  return i2c_ok; 
}

/******************************************************************************/
Status_I2C SelectDevice_I2C(I2C_TypeDef* I2Cx, const ReqArrayData_I2C *ReqData)
{
  uint32_t loopTimerOut;
  
  /* check I2C busy ? */
  loopTimerOut = TIMEOUT;
  while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY))
  {
    if (0 == loopTimerOut--)
    {
      return i2c_busy;
    }
  }
  
  /* start */
  loopTimerOut = TIMEOUT;
  I2C_GenerateSTART(I2Cx, ENABLE);
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (0 == loopTimerOut--)
    {
      return i2c_startError;
    }
  }
  
  /* device address */
  loopTimerOut = TIMEOUT;
  I2C_Send7bitAddress(I2Cx, ReqData->DeviceAddress_I2C, I2C_Direction_Transmitter);
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
  {
    if (0 == loopTimerOut--)
    {
      return i2c_addressSendFault;
    }
  }
  
  /* data address */
  loopTimerOut = TIMEOUT;
  I2C_SendData(I2Cx, ReqData->DataAddress_I2C);
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
  {
    if (0 == loopTimerOut--)
    {
      return i2c_dataSubaddressFault;
    }
  }
  return i2c_ok;
}


/******************************************************************************/
Status_I2C WritePolling_I2C(I2C_TypeDef* I2Cx, const ReqArrayData_I2C *ReqData)
{
  uint32_t loopTimerOut;
  uint8_t i;
  Status_I2C status;
  
  status = SelectDevice_I2C(I2Cx, ReqData);
  if (i2c_ok != status)
    return status;
  
  /* write data */
  i = 0;
  
  while(i < ReqData->DataLength_I2C)
  {
    loopTimerOut = TIMEOUT;
    I2C_SendData(I2Cx, ReqData->Data_I2C[i]);
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING))
    {
      if (0 == loopTimerOut--)
      {
        return i2c_dataSubaddressFault;
      }
    }
    i++;
  }
  
  /* stop */
  I2C_GenerateSTOP(I2Cx, ENABLE);
  return i2c_ok;
}

/******************************************************************************/
Status_I2C ReadPolling_I2C(I2C_TypeDef* I2Cx, ReqArrayData_I2C *ReqData)
{
  uint32_t loopTimerOut;
  uint8_t i;
  Status_I2C status;
  
  status = SelectDevice_I2C(I2Cx, ReqData);
  if (i2c_ok != status)
    return status;
  
  /* check I2C busy ? */
  loopTimerOut = TIMEOUT;
  while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BTF) == RESET)
  {
    if (0 == loopTimerOut--)
    {
      return i2c_repeatedStartFault;
    }
  }
  
  /* repeated start */
  loopTimerOut = TIMEOUT;
  I2C_GenerateSTART(I2Cx, ENABLE);
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT))
  {
    if (0 == loopTimerOut--)
    {
      return i2c_repeatedStartFault;
    }
  }
  
  /* repeated device address */
  loopTimerOut = TIMEOUT;
  I2C_Send7bitAddress(I2Cx, ReqData->DeviceAddress_I2C, I2C_Direction_Receiver);
  while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))
  {
    if (0 == loopTimerOut--)
    {
      return i2c_repeatedAddressFault;
    }
  }
  
  /* read data */
  i = 0;
  while(i < ReqData->DataLength_I2C)
  {
    loopTimerOut = TIMEOUT;
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED))
    {
      if (0 == loopTimerOut--)
      {
        return i2c_dataSubaddressFault;
      }
    }
    ReqData->Data_I2C[i] = I2C_ReceiveData(I2Cx);
    if (i == (ReqData->DataLength_I2C - 1))
    {
      /* stop */
      I2C_AcknowledgeConfig(I2Cx, DISABLE);
      I2C_GenerateSTOP(I2Cx, ENABLE);
    }    
    i++;
  }
  I2C_AcknowledgeConfig(I2Cx, ENABLE);
  return i2c_ok;
}


#ifdef __cplusplus
}
#endif
